Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Public Class frmGenerarMapaAleatorio
    Public MatrizCaminos(,,) As Integer
    Dim DistanciaMaxima As Integer
    Dim cantCiudades As Integer
    Dim autopista As Integer = 10
    Dim ruta As Integer = 5
    Dim tierra As Integer = 1
    Dim probabilidad As Decimal
    Dim generador As New Random()

    Public Sub New()
        Me.InitializeComponent()

        'Generar Ciudades
        For i As Integer = 2 To 15
            Me.cmbCantCiudades.Items.Add(i)
        Next
        Me.cmbCantCiudades.SelectedIndex = 0

        If File.Exists("MatrizSalvada.bin") Then
            Me.btnLoad.Enabled = True
        Else
            Me.btnLoad.Enabled = False
        End If
    End Sub

    Sub GenerarMatrizDinamica()
        'Tipo = 0 -> Autopista
        'Tipo = 1 -> Ruta
        'Tipo = 2 -> Tierra
        Dim tipo As Integer
        Dim distancia As Integer
        Dim random As Decimal

        ReDim Me.MatrizCaminos(cantCiudades - 1, cantCiudades - 1, 1)

        For i As Integer = 0 To cantCiudades - 1
            For j As Integer = i To cantCiudades - 1
                If i = j Then
                    MatrizCaminos(i, j, 0) = 0
                    MatrizCaminos(i, j, 1) = 0
                Else
                    random = Rnd()
                    If random <= Me.probabilidad Then
                        distancia = generador.Next(1, DistanciaMaxima)
                        tipo = generador.Next(0, 3)
                        MatrizCaminos(i, j, 0) = distancia
                        MatrizCaminos(j, i, 0) = distancia
                        If tipo = 0 Then
                            MatrizCaminos(i, j, 1) = autopista
                            MatrizCaminos(j, i, 1) = autopista
                        Else
                            If tipo = 1 Then
                                MatrizCaminos(i, j, 1) = ruta
                                MatrizCaminos(j, i, 1) = ruta
                            Else
                                MatrizCaminos(i, j, 1) = tierra
                                MatrizCaminos(j, i, 1) = tierra
                            End If
                        End If
                    Else
                        MatrizCaminos(i, j, 0) = 0
                        MatrizCaminos(j, i, 0) = 0
                        MatrizCaminos(i, j, 1) = 0
                        MatrizCaminos(j, i, 1) = 0
                    End If
                End If
            Next

            'Verifico que la fila tenga al menos un camino con otra ciudad
            Dim cantCaminos As Integer = 0
            For j As Integer = 0 To cantCiudades - 1
                If MatrizCaminos(i, j, 0) <> 0 Then
                    cantCaminos += 1
                End If
            Next
            If cantCaminos = 0 Then
                'Elijo una ciudad aleatoria verificando que no sea la misma de la fila
                Dim j As Integer = generador.Next(0, cantCiudades)
                While j = i
                    j = generador.Next(0, cantCiudades)
                End While
                distancia = generador.Next(1, DistanciaMaxima)
                tipo = generador.Next(0, 3)
                MatrizCaminos(i, j, 0) = distancia
                MatrizCaminos(j, i, 0) = distancia
                If tipo = 0 Then
                    MatrizCaminos(i, j, 1) = autopista
                    MatrizCaminos(j, i, 1) = autopista
                Else
                    If tipo = 1 Then
                        MatrizCaminos(i, j, 1) = ruta
                        MatrizCaminos(j, i, 1) = ruta
                    Else
                        MatrizCaminos(i, j, 1) = tierra
                        MatrizCaminos(j, i, 1) = tierra
                    End If
                End If
            End If
        Next

        'Sigo agregando caminos en forma aleatoria hasta obtener una matriz valida
        While (Not Funciones.Validar(Me.MatrizCaminos))
            Dim i As Integer
            Dim j As Integer
            Do
                i = Me.generador.Next(0, Me.MatrizCaminos.GetUpperBound(0))
                j = Me.generador.Next(0, Me.MatrizCaminos.GetUpperBound(0))
            Loop While (i = j And Me.MatrizCaminos(i, j, 0) <> 0) 'Origen y destino no deben ser iguales, y no debe haber un camino ya entre ambos

            distancia = generador.Next(1, DistanciaMaxima)
            tipo = generador.Next(0, 3)
            MatrizCaminos(i, j, 0) = distancia
            MatrizCaminos(j, i, 0) = distancia
            If tipo = 0 Then
                MatrizCaminos(i, j, 1) = autopista
                MatrizCaminos(j, i, 1) = autopista
            Else
                If tipo = 1 Then
                    MatrizCaminos(i, j, 1) = ruta
                    MatrizCaminos(j, i, 1) = ruta
                Else
                    MatrizCaminos(i, j, 1) = tierra
                    MatrizCaminos(j, i, 1) = tierra
                End If
            End If
        End While
    End Sub

    Sub MostrarMatrizCaminos()
        Dim dtDistancias As New DataTable()
        Dim dr As DataRow

        'Genero los encabezados de las columnas
        For i As Integer = 1 To Me.MatrizCaminos.GetUpperBound(0) + 1
            dtDistancias.Columns.Add(i)
        Next

        'Cargo el DataTable con los valores de los caminos
        For j As Integer = 0 To Me.MatrizCaminos.GetUpperBound(0)
            dr = dtDistancias.NewRow()
            For k As Integer = 0 To Me.MatrizCaminos.GetUpperBound(1)
                'Esto es para que solo se muestren los caminos que existan (Distantia <> 0)
                If Me.MatrizCaminos(j, k, 0) <> 0 Then
                    'Muestro el camino en el formato "Distancia(Aptitud)"
                    dr.Item(k) = Me.MatrizCaminos(j, k, 0).ToString() & "(" & Me.MatrizCaminos(j, k, 1).ToString() & ")" '
                End If
            Next
            dtDistancias.Rows.Add(dr)
        Next

        'Paso el datatable de los caminos al datagridview
        Me.dgvCiudades.DataSource = ""
        Me.dgvCiudades.DataSource = dtDistancias

        'Genero los encabezados de las filas
        For k As Integer = 0 To Me.MatrizCaminos.GetUpperBound(0)
            Dim Encabezado As String = (k + 1).ToString()
            Me.dgvCiudades.Rows(k).HeaderCell.Value = Encabezado
        Next

        PuntosEstaticos.cargarPuntos()
        Ciudad.crearCiudades(MatrizCaminos.GetUpperBound(0))
        Camino.crearCaminos(MatrizCaminos)

        Me.Refresh()
    End Sub

    Private Sub btnGenerar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGenerar.Click
        Randomize()
        Me.DistanciaMaxima = Me.txbDistanciaMax.Value
        Me.probabilidad = Me.txbProbabilidad.Value
        Me.cantCiudades = Me.cmbCantCiudades.SelectedItem
        Me.btnAceptar.Enabled = True
        Me.btnMapa.Enabled = True
        Me.btnSave.Enabled = True
        Me.GenerarMatrizDinamica()
        Me.MostrarMatrizCaminos()
    End Sub

    Private Sub btnMapa_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMapa.Click
        Dim form As New frmGrafo(Me.MatrizCaminos)
        form.Show()
        form.Refresh()
    End Sub

    Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAceptar.Click
        If Funciones.Validar(Me.MatrizCaminos) Then
            Me.Close()
        Else
            MessageBox.Show("Error: La matriz no esta totalmente conectada")
        End If
    End Sub

    Private Sub btnSalir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalir.Click
        Dim nuevamatriz(,,) As Integer
        Me.MatrizCaminos = nuevamatriz
        Me.Close()
    End Sub

    Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click
        If File.Exists("MatrizSalvada.bin") Then
            Dim myFileStream As Stream = File.OpenRead("MatrizSalvada.bin")
            Dim deserializer As New BinaryFormatter()
            Dim matrizSalvada As New Matrices()
            matrizSalvada = CType(deserializer.Deserialize(myFileStream), proyectoia.Matrices)
            myFileStream.Close()
            Me.MatrizCaminos = matrizSalvada.Caminos
        End If
        Me.cmbCantCiudades.SelectedIndex = Me.MatrizCaminos.GetUpperBound(0) - 1
        Me.MostrarMatrizCaminos()
        Me.btnAceptar.Enabled = True
        Me.btnMapa.Enabled = True
        Me.btnSave.Enabled = True
    End Sub

    Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
        Dim matriz As New Matrices()
        matriz.Caminos = Me.MatrizCaminos
        Dim myFileStream As Stream = File.Create("MatrizSalvada.bin")
        Dim serializer As New BinaryFormatter()
        serializer.Serialize(myFileStream, matriz)
        myFileStream.Close()
        Me.btnLoad.Enabled = True
        MessageBox.Show("Matriz guardada correctamente")
    End Sub

    Sub guardarAtexto()
        Dim cant As Integer = Me.MatrizCaminos.GetUpperBound(0) + 1
        Dim oSW As New System.IO.StreamWriter("D:\matriz_" + cant.ToString() + "_ciudades.txt")
        For i As Integer = 0 To Me.MatrizCaminos.GetUpperBound(0)
            For j As Integer = 0 To Me.MatrizCaminos.GetUpperBound(1)
                Dim distancia As String = Me.MatrizCaminos(i, j, 0)
                Dim tipo As String = Me.MatrizCaminos(i, j, 1)
                Dim linea As String = "Me.MatrizCaminos(" & i.ToString() & " , " & j.ToString() & " , 0) = " & distancia
                oSW.WriteLine(linea)
                linea = "Me.MatrizCaminos(" & i.ToString() & " , " & j.ToString() & " , 1) = " & tipo
                oSW.WriteLine(linea)
            Next
        Next
        oSW.Flush()
    End Sub
End Class